package com.skyline.courier.net.provider.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import com.skyline.courier.net.AbstractServer;
import com.skyline.courier.net.Statistic;

public class NettyServer extends AbstractServer {
	private ServerBootstrap serverBootstrap;
	private int bossThreads = -1;
	private int workerThreads = -1;
	private NioEventLoopGroup bossLoopGroup;
	private NioEventLoopGroup workerLoopGroup;
	private Statistic statistic = new Statistic();
	
	public void setBossThreads(int bossThreads) {
		this.bossThreads = bossThreads;
	}
	
	public void setWorkerThreads(int workerThreads) {
		this.workerThreads = workerThreads;
	}
	

	@Override
	protected void doBind(int port) {
		initEventLoopGroup();
		initBootstrap();
		serverBootstrap.bind(port).awaitUninterruptibly();
	}

	private void initBootstrap() {
		serverBootstrap = new ServerBootstrap();
		serverBootstrap.group(bossLoopGroup, workerLoopGroup);
		serverBootstrap.channel(NioServerSocketChannel.class);
		
		serverBootstrap.option(ChannelOption.TCP_NODELAY, getTcpNoDelay());
		serverBootstrap.option(ChannelOption.SO_KEEPALIVE, getKeepAlive());
		serverBootstrap.option(ChannelOption.SO_REUSEADDR, getReuseAddress());
		serverBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getConnectTimeout());
		
		NettyServerInitializer initializer = new NettyServerInitializer();
		initializer.setSerializer(getSerializer());
		initializer.setReadIdleTime(getReadIdleTime());
		initializer.setWriteIdleTime(getWriteIdleTime());
		initializer.setStatistic(statistic);
		initializer.setHandler(handler);
		serverBootstrap.childHandler(initializer);
	}

	private void initEventLoopGroup() {
		if(bossThreads == -1) {
			bossLoopGroup = new NioEventLoopGroup();
		} else {
			bossLoopGroup = new NioEventLoopGroup(bossThreads);
		}
		if(workerThreads == -1) {
			workerLoopGroup = new NioEventLoopGroup();
		} else {
			workerLoopGroup = new NioEventLoopGroup(workerThreads);
		}
	}

	@Override
	protected void doShutdown() {
		bossLoopGroup.shutdownGracefully();
		workerLoopGroup.shutdownGracefully();
		serverBootstrap = null;
	}

}
